﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using ESpace;
using System.IO;
using System.Net;

namespace OrdonnanceAdmin
{
    public partial class Form1 : Form
    {
        bool isLogin = false;
        public bool serverIsAvailable
        {
            get
            {
                return clnt.IsConnect & isLogin;
            }
        }
        List<byte[]> sendL = new List<byte[]>();
        int cntSend = 0;
        byte idQuery = 0;
        List<Game> gmL = new List<Game>();
        bool bWait { get { return idQuery != 0; } }

        class Game
        {
            public String name;
            public bool GameIsPlay = false;
            public List<User> pl = new List<User>();
            public String moder { get { return pl[0].name; } }
            public Game(String Name, String Moder)
            {
                name = Name;
                pl.Add(new User(Moder));
            }
        }

        class User
        {
            public String name = "";
            public String pass = "";
            public String addr = "";
            public bool bot = false;
            public User(String Name, bool Bot)
            {
                name = Name;
                bot = Bot;
            }
            public User(String Addr)
            {
                addr = Addr;
            }
        }

        List<User> cl = new List<User>();

        public Form1()
        {
            InitializeComponent();

            LoadConnectSettings(clnt);

            if (!clnt.Connect())
            {
                MessageBox.Show("Не удалось подключиться к серверу");
            }
            else
            {
                LogIn();
            }
            SetEnabledBtn();
        }

        void LoadConnectSettings(ETcpClient client)
        {
            String fName = "ConnectSettings.txt";
            if (!File.Exists(fName))
            {
                String[] strl = new String[2];
                strl[0] = "127.0.0.1 //IP-адрес сервера";
                strl[1] = "654 //порт сервера";
                File.WriteAllLines(fName, strl, Encoding.Default);
            }

            // загружаем настройки
            String[] sl = File.ReadAllLines(fName, Encoding.Default);
            if (sl.Length != 2) return;
            String[] sl1 = sl[0].Split(' ');
            if (sl1.Length < 1) return;
            String strIp = sl1[0];
            IPAddress ip = ETcp.GetAddr(strIp);
            if (ip == null) return;
            int p = 0;
            sl1 = sl[1].Split(' ');
            if (sl1.Length < 1) return;
            if (!int.TryParse(sl1[0], out p)) return;

            client.ServerIP = strIp;
            client.ServerPort = p;
        }

        Random rnd = new Random();
        byte cnt = 0;
        private void tmrSend_Tick(object sender, EventArgs e)
        {
            try
            {
                SetEnabledBtn();
                if (!serverIsAvailable)
                {
                    return;
                }
                if (cntSend < 20)
                {
                    cntSend++;
                    return;
                }
                // если есть, что отправлять, отправляем и сбрасываем счетчик ожидания
                if (sendL.Count > 0)
                {
                    // пробуем отправить.
                    if (!clnt.Send(sendL[0]))
                    {
                        MessageBox.Show("Не удалось отправить очередное сообщение на сервер.");
                        isLogin = false;
                    }
                    else
                    {
                        sendL.RemoveAt(0);
                    }
                    cntSend = 0;
                }
                // если отправлять нечего, можно отправить паразита
                else if(chbxParasite.Checked)
                {
                    String s = "";
                    byte[] b = new byte[rnd.Next(5000) + 1];
                    for (int i = 1; i < b.Length; i++)
                    {
                        b[i] = (byte)rnd.Next(256);
                        if(i<10) s += " " + b[i].ToString();
                    }
                    cnt++;
                    if (cnt > 51) cnt = 1;
                    b[0] = cnt;
                    //b[0] = (byte)rnd.Next(60);
                    s = b[0].ToString() + s;
                    // пробуем отправить.
                    if (!clnt.Send(b))
                    {
                        MessageBox.Show("Не удалось отправить очередное сообщение на сервер.");
                        isLogin = false;

                    }
                    else
                    {
                        AddLog("Отправлен пакет-паразит. Перв байты: " + s);
                    }
                    cntSend = 0;
                }
            }
            catch (Exception ex) { MessageBox.Show("Ошибка отправки очередного сообщения: " + ex.Message); }
        }

        List<String> log = new List<String>();
        void AddLog(String s)
        {
            log.Add(DateTime.Now.ToString() + " >> " + s);
            if (log.Count > 1000) log.RemoveAt(0);
            if (chbxUpdLog.Checked) UpdateLog();
        }

        void UpdateLog()
        {
            int StartI = log.Count - 100; if (StartI < 0) StartI = 0;
            StringBuilder s = new StringBuilder();
            for (int i = StartI; i < log.Count; i++)
            {
                s.AppendLine(log[i]);
            }
            txbLog1.Text = s.ToString();
            txbLog1.Select(txbLog1.Text.Length, 0);
            txbLog1.ScrollToCaret();
        }

        void ShowAllLog()
        {
            for (int i = 0; i < log.Count; i++)
            {
                txbLog1.Text += log[i] + "\r\n";
            }
        }

        void RefillClientList()
        {
            try
            {
                lbList.Items.Clear();
                for (int i = 0; i < cl.Count; i++)
                {
                    if (cl[i].name == "") lbList.Items.Add("Неизвестное подключение " + cl[i].addr);
                    else
                    {
                        String s = cl[i].name;
                        if (cl[i].addr != "") s += " >> " + cl[i].addr;
                        lbList.Items.Add(s);
                    }
                }
                RefillGameList();
            }
            catch(Exception ex) { MessageBox.Show("Ошибка обновления листа клиентов: " + ex.Message); }
        }

        void RefillGameList()
        {
            tvGames.Nodes.Clear();
            try
            {
            for (int i = 0; i < gmL.Count; i++)
            {
                int idModer = GetIdByName(cl, gmL[i].moder);
                String s = gmL[i].name + " <<" + gmL[i].moder + ">>";
                if (idModer == -1)
                    s = gmL[i].name + " " + gmL[i].moder;

                // если игра играется
                if (gmL[i].GameIsPlay)
                {
                    s = "***" + s + "***";
                }
                tvGames.Nodes.Add(s);

                for (int j = 1; j < gmL[i].pl.Count; j++)
                {
                    s = " <<" + gmL[i].pl[j].name + ">>";
                    if (!gmL[i].pl[j].bot)
                    {
                        int id = GetIdByName(cl, gmL[i].pl[j].name);
                        if (id == -1)
                            s = cl[id].name;
                    }
                    tvGames.Nodes[tvGames.Nodes.Count - 1].Nodes.Add(s);
                }
            }

            tvGames.ExpandAll();
            }
            catch(Exception ex) { MessageBox.Show("Ошибка обновления листа игр: " + ex.Message); }
        }

        bool UserIsOnLine(String name)
        {
            for (int i = 0; i < cl.Count; i++)
                if (cl[i].name == name) return true;
            return false;
        }

        int GetIdByName(List<User> cl, String name)
        {
            for (int i = 0; i < cl.Count; i++)
                if (Name == cl[i].name) return i;
            return -1;
        }

        int GetIdGameByName(List<Game> gl, String name)
        {
            for (int i = 0; i < gl.Count; i++)
                if (Name == gl[i].name) return i;
            return -1;
        }

        #region *** события ********************************************

        private void btnUpdateUsers_Click(object sender, EventArgs e)
        {
            if (bWait) return;
            // подготавливаем пакет
            byte[] buf = new byte[1] { 11 };
            sendL.Add(buf);
            idQuery = 11;
        }

        // кнопка запроса на обновление листа игр (17)
        private void btnUpdateGames_Click(object sender, EventArgs e)
        {
            if (bWait) return;
            // подготавливаем пакет
            byte[] buf = new byte[1] { 12 };
            sendL.Add(buf);
            idQuery = 12;
        }

        private void btnUpdateLog_Click(object sender, EventArgs e)
        {
            if (bWait) return;
            // подготавливаем пакет
            byte[] buf = new byte[1] { 13 };
            sendL.Add(buf);
            idQuery = 13;
        }

        private void btnDelUser_Click(object sender, EventArgs e)
        {
            if (bWait) return;
            int ind = lbList.SelectedIndex;
            if (lbList.SelectedIndex == -1) return;
            String clName = cl[ind].name;
            if (clName == "") return;
            // подготавливаем пакет
            BufWriter bw = new BufWriter();
            bw.WriteByte(14);
            bw.WriteString(clName);
            sendL.Add(bw.buf);
            idQuery = 14;
        }

        private void btnChangePass_Click(object sender, EventArgs e)
        {
            if (bWait) return;
            int ind = lbList.SelectedIndex;
            if (ind==-1) return;
            if (cl[ind].name == "") return;
            String newPass = txbPass.Text.Trim();
            if (newPass == "")
            {
                MessageBox.Show("Пароль не может быть пустым");
                return;
            }

            // подготавливаем пакет
            BufWriter bw = new BufWriter();
            bw.WriteByte(16);
            bw.WriteString(cl[ind].name);
            bw.WriteString(newPass);
            sendL.Add(bw.buf);
            idQuery = 16;
        }

        private void btnKikUser_Click(object sender, EventArgs e)
        {
            if (bWait) return;
            int ind = lbList.SelectedIndex;
            if (lbList.SelectedIndex == -1) return;
            // подготавливаем пакет
            BufWriter bw = new BufWriter();
            bw.WriteByte(17);
            bw.WriteString(cl[ind].addr);
            sendL.Add(bw.buf);
            idQuery = 17;
        }

        private void btnDelGame_Click(object sender, EventArgs e)
        {
            if (bWait) return;
            if (tvGames.SelectedNode == null) return;
            int idGame = GetIdGameByName(gmL, tvGames.SelectedNode.Text);
            if (idGame == -1) return;
            // подготавливаем пакет
            BufWriter bw = new BufWriter();
            bw.WriteByte(15);
            bw.WriteString(gmL[idGame].name);
            sendL.Add(bw.buf);
            idQuery = 15;
        }

        private void btnRelogin_Click(object sender, EventArgs e)
        {
            if (serverIsAvailable)
            {
                if (MessageBox.Show("Подключение к серверу сейчас есть. Переподключиться?", "Переподключение к серверу", MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.No)
                {
                    SetEnabledBtn();
                    return;
                }
            }
            if (clnt.IsConnect) clnt.Disconnect();
            isLogin = false;
            if (!clnt.Connect())
            {
                MessageBox.Show("Не удалось подключиться к серверу");
                SetEnabledBtn();
                return;
            }
            LogIn();
            SetEnabledBtn();
        }

        private void tvGames_AfterSelect(object sender, TreeViewEventArgs e)
        {
            //
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            clnt.Disconnect();
        }

        #endregion *** события ********************************************

        void LogIn()
        {
            // отправляем данные
            BufWriter bw = new BufWriter();
            bw.WriteByte(1);
            bw.WriteString("Администратор");
            bw.WriteString("Хочу все знать!");
            if (!clnt.Send(bw.buf))
            {
                MessageBox.Show("Не удалось отправить даные логина на сервер");
            }
            else
            {
                cntSend = 0;
            }
        }

        #region *** Прием **********************************************************

        private void clnt_OnRecive(object Sender, ETcpClient.RecvEventArgs e)
        {
            try
            {
                byte[] buf = e.buf;

                if (buf[0] == 1) LogIn(buf);
                // обновить список юзеров
                if (buf[0] == 11) UpdateListClients (buf);
                // обновить список игр
                if (buf[0] == 12) UpdateListGames(buf);
                // обновить лог
                if (buf[0] == 13)UpdateLog(buf);
                
                // удалить юзера
                if (buf[0] == 14) AnsDeleteUser(buf);
                // удалить юзера
                if (buf[0] == 15) AnsDeleteGame(buf);
                // удалить юзера
                if (buf[0] == 16) AnsChangePass(buf);
                // удалить юзера
                if (buf[0] == 17) AnsKickClient(buf);

                SetEnabledBtn();

            }
            catch (Exception ex) { MessageBox.Show("Ошибка приема данных: " + ex.Message); }
        }

        #region *** обновления ************************************************

        // ответ - обновление листа клиентов (11)
        void UpdateListClients(byte[] buf)
        {
            idQuery = 0;
            BufReader br = new BufReader(buf);
            br.ReadByte();
            UpdListClients(br);

        }
        // ответ - обновление листа игр (12)
        void UpdateListGames(byte[] buf)
        {
            idQuery = 0;
            BufReader br = new BufReader(buf);
            br.ReadByte();
            UpdListGames(br);
        }

        void UpdListClients(BufReader br)
        {
            cl.Clear();
            try
            {
                // клиенты
                int kolvoCl = br.ReadInt();
                for (int i = 0; i < kolvoCl; i++)
                {
                    String name = br.ReadString();
                    String pass = br.ReadString();
                    String addr = br.ReadString();
                    User u = new User(addr);
                    u.name = name;
                    u.pass = pass;
                    cl.Add(u);
                }
                // неизвестные подключения
                kolvoCl = br.ReadInt();
                for (int i = 0; i < kolvoCl; i++)
                {
                    String addr = br.ReadString();
                    cl.Add(new User(addr));
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Ошибка разбора пакета Обновление листа клиентов >> " + ex.Message);
            }
            RefillClientList();
        }

        void UpdListGames(BufReader br)
        {
            gmL.Clear();
            try
            {
                int kolvoGames = br.ReadInt();
                for (int i = 0; i < kolvoGames; i++)
                {
                    String nm = br.ReadString();
                    int kolvoUsers = br.ReadInt();
                    bool bPlay = br.ReadByte() == 1;
                    String Moder = br.ReadString();
                    bool bot = false;
                    bot = br.ReadByte() == 1;
                    gmL.Add(new Game(nm, Moder));
                    int ind = gmL.Count - 1;
                    gmL[ind].GameIsPlay = bPlay;
                    // список игроков
                    for (int j = 1; j < kolvoUsers; j++)
                    {
                        String nmPl = br.ReadString();
                        bot = br.ReadByte() == 1;
                        gmL[ind].pl.Add(new User(nmPl, bot));
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Ошибка разбора пакета Обновление листа игр >> " + ex.Message);
            }
            RefillGameList();
        }

        // ответ - обновление лога (13)
        void UpdateLog(byte[] buf)
        {
            idQuery = 0;
            BufReader br = new BufReader(buf);
            try
            {
                br.ReadByte();
                txbLog.Text = br.ReadString();
                
            }
            catch (Exception ex)
            {
                MessageBox.Show("Ошибка разбора пакета Обновление лога >> " + ex.Message);
            }
        }

        #endregion *** обновления ************************************************

        #region *** ответы *********************

        void LogIn(byte[] buf)
        {
            idQuery = 0;
            if (buf[1] != 0)
            {
                if (buf[1] == 3)
                {
                    MessageBox.Show("Ошибка логина: Такой пользователь уже залогинен на этом сервере");

                }
                else
                {
                    MessageBox.Show("Ошибка логина: Пользователь с таким логином и паролем не зарегистрирован.");
                }
            }
            // удачный логин
            if (buf[1] == 0)
            {
                //MessageBox.Show("Логин на сервер удачен");
                isLogin = true;
            }
        }

        // ответ - удаление юзера (14)
        void AnsDeleteUser(byte[] buf)
        {
            idQuery = 0;
            BufReader br = new BufReader(buf);
            try
            {
                br.ReadByte();
                byte err = br.ReadByte();
                if (err == 10) MessageBox.Show("Не удалась проверка админских прав. Попробуйте переподключиться");
                if (err == 1) MessageBox.Show("Такого юзера уже нет на сервере");
                if (err == 0)
                {
                    MessageBox.Show("Юзер удален");
                    UpdListClients(br);
                }
            }
            catch { MessageBox.Show("Ошибка разбора пакета: удаление юзера"); }
        }

        // ответ - удаление игры (15)
        void AnsDeleteGame(byte[] buf)
        {
            idQuery = 0;
            BufReader br = new BufReader(buf);
            try
            {
                br.ReadByte();
                byte err = br.ReadByte();
                if (err == 10) MessageBox.Show("Не удалась проверка админских прав. Попробуйте переподключиться");
                if (err == 1) MessageBox.Show("Такой игры уже нет на сервере");
                if (err == 0)
                {
                    UpdListGames(br);
                    MessageBox.Show("Игра удалена");
                }
            }
            catch { MessageBox.Show("Ошибка разбора пакета: удаление игры"); }
        }

        // ответ - смена пароля юзеру (16)
        void AnsChangePass(byte[] buf)
        {
            idQuery = 0;
            BufReader br = new BufReader(buf);
            try
            {
                br.ReadByte();
                byte err = br.ReadByte();
                if (err == 10) MessageBox.Show("Не удалась проверка админских прав. Попробуйте переподключиться");
                if (err == 1) MessageBox.Show("Такого юзера уже нет");
                if (err == 2) MessageBox.Show("Пароль некорректен");
                if (err == 0)
                {
                    UpdListClients(br);
                    MessageBox.Show("Пароль успешно изменен");
                }
            }
            catch { MessageBox.Show("Ошибка разбора пакета: смена пароля юзеру"); }
        }

        // ответ - кикнуть клиента (17)
        void AnsKickClient(byte[] buf)
        {
            idQuery = 0;
            BufReader br = new BufReader(buf);
            try
            {
                br.ReadByte();
                byte err = br.ReadByte();
                if (err == 10) MessageBox.Show("Не удалась проверка админских прав. Попробуйте переподключиться");
                if (err == 1) MessageBox.Show("Такого клиента уже нет в списке");
                if (err == 0)
                {
                    UpdListClients(br);
                    MessageBox.Show("Клиент успешно отключен");
                }
            }
            catch { MessageBox.Show("Ошибка разбора пакета: отключить клиента"); }
        }

        #endregion *** ответы *********************

        #endregion *** Прием **********************************************************

        void SetEnabledBtn()
        {
            btnUpdateUsers.Enabled = !bWait && serverIsAvailable;
            btnUpdateGames.Enabled = !bWait && serverIsAvailable;
            btnUpdateLog.Enabled = !bWait && serverIsAvailable;

            bool b = !bWait && serverIsAvailable;
            if (b)
            {
                b = false;
                if (lbList.SelectedIndex != -1)
                    b = cl[lbList.SelectedIndex].name != "";
            }
            btnDelUser.Enabled = b;
            btnChangePass.Enabled = b;

            b = !bWait && serverIsAvailable;
            if (b)
            {
                b = false;
                /*if (tvGames.SelectedNode != null)
                {
                    b = GetIdGameByName();
                }*/
            }
            btnDelGame.Enabled = b;

            b = !bWait && serverIsAvailable;
            if (b)
            {
                b = false;
                if (lbList.SelectedIndex != -1)
                    b = cl[lbList.SelectedIndex].addr != "";
            }
            btnKikUser.Enabled = b;
        }

        private void lbList_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (lbList.SelectedIndex == -1)
            {
                txbPass.Text = "";
                return;
            }

            txbPass.Text = cl[lbList.SelectedIndex].pass;
        }

        private void chbxUpdLog_CheckedChanged(object sender, EventArgs e)
        {
            if (chbxUpdLog.Checked) UpdateLog();
        }
    }
}
